package com.gitee.wsl.compose.ui.popup

import androidx.compose.animation.animateColor
import androidx.compose.animation.core.EaseIn
import androidx.compose.animation.core.FiniteAnimationSpec
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.core.Transition
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.updateTransition
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.window.DialogProperties
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupProperties
import com.gitee.wsl.compose.ui.base.Popup

@Composable
fun Popup.AnimatedSheet(
    visible: Boolean,
    onDismissRequest: () -> Unit,
    properties: DialogProperties = DialogProperties(),
    scrimColor : Color = Color.Black.copy(alpha = .4f),
    content: @Composable() (BoxScope.() -> Unit)
) {

    val expandedStates = remember { MutableTransitionState(false) }

    expandedStates.targetState = visible

    if (expandedStates.currentState || expandedStates.targetState) {

        val haptic = LocalHapticFeedback.current
        Popup(
            onDismissRequest = onDismissRequest,
            properties = PopupProperties(
                dismissOnBackPress = properties.dismissOnBackPress,
                dismissOnClickOutside = properties.dismissOnClickOutside,
                //usePlatformDefaultWidth = false,
            )
        ) {
            CompositionLocalProvider(LocalHapticFeedback provides haptic) {

                val transition = updateTransition(expandedStates, "CupertinoSheet")

                val animatedScrimColor by transition.animateColor(
                    transitionSpec =  {
                        sheetAnimation()
                    }, label = ""
                ) {
                    if (it) scrimColor else scrimColor.copy(alpha = 0f)
                }

                val transitionProgress by transition.animateFloat(
                    transitionSpec = {
                        sheetAnimation()
                    }, label = ""
                ) {
                    if (it) 0f else 1f
                }

                Box(
                    modifier = Modifier
                        .fillMaxSize()
                        .drawWithContent {
                            drawRect(animatedScrimColor)
                            drawContent()
                        }
                        .let {
                            if (properties.dismissOnClickOutside && visible)
                                it.pointerInput(0) {
                                    detectTapGestures {
                                        onDismissRequest()
                                    }
                                } else it
                        }
                ) {

                    Box(
                        modifier = Modifier
                            .fillMaxSize()
                            .graphicsLayer {
                                translationY = size.height * transitionProgress
                            },
                        content = content
                    )
                }
            }
        }
    }
}

private fun <T> Transition.Segment<Boolean>.sheetAnimation() : FiniteAnimationSpec<T> =
    if (true isTransitioningTo false) {
        tween(
            durationMillis = 150,
            easing = EaseIn
        )
    } else {
        tween()
    }